#ifndef LCOM_WINDOW_H
#define LCOM_WINDOW_H

/** \brief Janela
 */
typedef struct Window_ *Window;

/** \brief Assinatura da função que desenha as janelas
 * \param win Janela
 * \param x Coordenada X do retângulo a ser desenhado
 * \param y Coordenada Y do retângulo
 * \param w Largura do retângulo
 * \param h Altura do retângulo
 * \param data Dados associados à janela
 */
typedef void (* WindowDrawFunc) (Window win, int x, int y, int w, int h, void *data);

/** Assinaturas de função de update do estado da janela
 * \param win Janela
 * \param data Dados associados à janela
 */
typedef void (* WindowUpdateFunc) (Window win, void *data);

/** \brief Resoluções
 */
enum Resolution {
	R640x480 = 0x101,
	R800x600 = 0x103,
	R1024x768 = 0x105,
	R1280x1024 = 0x107
};

/** \brief Planos onde a janela pode estar.
 *
 * Para criar vários subplanos pode-se somar um numero ao identificador
 * de plano. Quanto maior o número mais na frente está a janela.
 * Por exemplo: PLANE_BACKGROUND + 1 corresponde a um plano acima do plano
 * de fundo padrão e abaixo do plano PLANE_BACKGROUND + 2
 */
enum WindowPlane {
	/** \brief Planos de Fundo
	 * Estes planos estão atrás de todos os objectos com os quais se interage
	 */
	PLANE_BACKGROUND = 0,
	/** \brief Planos com paredes
	 * 
	 * Nestes planos ficam as paredes que podem bloquear o movimento do jogador
	 */
	PLANE_WALL = 0x1000000,
	/** \brief Planos com objectos
	 *
	 * Aqui ficam os objectos com os quais o jogador pode interagir
	 */
	PLANE_OBJECT = 0x2000000,
	/** \brief Plano com inimigos
	 */
	PLANE_ENEMY = 0x3000000,
	/** \brief Plano onde ficam os jogadores
	 */
	PLANE_PLAYER = 0x4000000,
	/** \brief Planos extra com função indefinida
	 */
	PLANE_EXTRA = 0x5000000, 	
	/** \brief Plano com os menus
	 */
	PLANE_MENU = 0x6000000
};

/** Indica que nenhuma cor é transparente nas funções de desenhar imagens */
#define COLOR_NOT_TRANS 0xFF00

/** \brief Inicializa o sistema de janelas
 *
 * \param res Resolução da tela
 */
void winsys_init (enum Resolution res); 


/** \brief Encerra o sistema de janelas
 */
void winsys_finish (void);

/** \brief Sai do modo gráfico sem destruir as janelas
 */
void winsys_textmode (void);

/** \brief Reentra no modo gráfico
 */
void winsys_graphicmode(enum Resolution res); 

/** \brief Destroi todas as janelas
 *
 * \warning Após a chamada desta função nenhum objecto Window previamente criado é válido
 */
void winsys_clear (void);

/** \brief Altera as coordenadas do sistema de janelas
 *
 * \param x Posição que corresponde ao 0 horizontal no ecrã
 * \param y Posição que corresponde ao 0 vertical no ecrã
 */
void winsys_set_coord (int x, int y);


/** \brief Obtém as coordenadas do sistema de janelas que correspondem à origem do ecrã
 *
 * \param x Endereço onde é retornada a coordenada x
 * \param y Endereço onde é retornada a coordenada y
 */
void winsys_get_coord (int *x, int *y);

/** \brief Altera as coordenadas do sistema de janelas baseando-se nas coordenadas antigas
 *
 * \param dx Variação na coordenada x
 * \param dy Variação na coordenada y
 */
void winsys_set_diff_coord (int dx, int dy);

/** \brief Envia um evento às janelas dizendo que elas devem ser atualizadas
 */
void winsys_update (void);

/** \brief Desenha as janelas na tela
 */
void winsys_draw (void);

/** \brief Cria uma janela
 *
 * \param x Posição horizontal da janela na tela
 * \param y Posição vertical da janela na tela
 * \param w Largura da janela
 * \param h Altura da janela
 * \param data Dados associados à janela
 * \return Uma nova janela com as especificações dadas
 */
Window window_new (int x, int y, int w, int h, void *data);


/** \bried Destroi uma janela
 *
 * \param win Janela a ser destruída
 */
void window_delete (Window win);


/** \brief Obtém o retângulo da da janela
 *
 * \param win Janela
 * \param x Coordenada X do canto superior esquerdo da janela
 * \param y Coordenada Y do canto superior esquerdo da janela
 * \param w Largura da janela
 * \param h Altura da janela
 */
void window_get_rect (Window win, int *x, int *y, int *w, int *h);


/** \brief Move a janela para uma nova posição
 *
 * \param win Janela a ser movida
 * \param x Nova posição horizontal
 * \param y Nova posição vertical
 */
void window_move (Window win, int x, int y);

/** \brief Move a janela para uma nova posição relativa à actual
 *
 * \param win Janela a ser movida
 * \param dx Variação horizontal
 * \param dy Variação vertical
 */
void window_move_diff (Window win, int dx, int dy);


/** \brief Torna a janela visível
 *
 * \param win Janela a ser mostrada
 * \param draw Função que desenha a janela
 */
void window_show (Window win, WindowDrawFunc draw);


/** \brief Oculta uma janela
 *
 * \param win Janela a ser ocultada
 */
void window_hide (Window win); 

/** \brief Requisita que a janela receba eventos "update"
 *
 * \param win Janela
 * \param update Função que efetua o update da janela
 */
void window_update (Window win, WindowUpdateFunc update);

/** \brief Define em qual o plano a janela está. 
 *
 * \param win Janela
 * \param plane Plano onde a janela está.
 */
void window_set_plane (Window win, enum WindowPlane plane);

/** Passa uma função para liberar os recursos usados pelos dados quando a janela é destruída
 *
 * \param win Janela
 * \param func Função que remove os recursos
 */
void window_set_free (Window win, void (*func) (void *data));
 

/** \brief Desenha uma imagem na janela
 *
 * \param win Janela
 * \param img_data Dados da imagem
 * \param img_w Largura da imagem
 * \param img_h Altura da imagem
 * \param transp Cor transparente
 */
#define window_image(win,image_data,img_w,img_h,transp) \
 	window_image_xy ((win), 0, 0, (image_data), (img_w), (img_h), (transp))

/** \brief Desenha uma imagem na janela nas dadas coordenadas
 *
 * \param win Janela
 * \param x Coordenada X de onde por a imagem
 * \param y Coordenada Y de onde por a imagem
 * \param img_data Dados da imagem
 * \param img_w Largura da imagem
 * \param img_h Altura da imagem
 * \param transp Cor transparente
 */
void window_image_xy (Window win,
			int x,
			int y,
			const unsigned char *img_data,
			int img_w,
			int img_h,
			int transp);

/** \brief Desenha uma imagem com o tamanho da janela
 *
 * \param win Janela
 * \param img_data Dados da imagem
 * \param transp Cor transparente
 */
void window_fill_image (Window win,
			const unsigned char *img_data,
			char transp);

/** \brief Desenha uma imagem na janela. O primeiro pixel da imagem corresponde à cor transparente
 * \param win Janela
 * \param img_data Dados da imagem
 * \param img_w Largura da imagem
 * \param img_h Altura da imagem
 * \warning img_data é avaliado mais de uma vez.
 */
#define window_image_corner(win,img_data,img_w,img_h) \
 		window_image_xy( (win), 0, 0, (img_data), (img_w), (img_h), *(img_data))

/** \brief Preenche a janela com uma cor
 *
 * \param win Janela
 * \param c Cor
 */
void window_fill (Window win, char c);

/** \brief Desenha uma linha na janela
 *
 * \param win Janela
 * \param x1 Coordenada x do primeiro ponto
 * \param y1 Coordenada y do primeiro ponto
 * \param x2 Coordenada x do segundo ponto
 * \param y2 Coordenada y do segundo ponto
 * \param c Cor da linha
 */
void window_draw_line (Window win, int x1, int y1, int x2, int y2, char c);

/** \brief Desenha um ponto na janela
 *
 * \param win Janela
 * \param x Coordenada x do ponto
 * \param y Coordenada y do ponto
 * \param c Cor do ponto
 */
void window_draw_point (Window win, int x, int y, char c);

/** \brief Desenha um caracter na janela
 *
 * \param win Janela
 * \param ch Caracter
 * \param x Coordenada x do ponto
 * \param y Coordenada y do ponto
 * \param color Cor do caracter
 */
void window_draw_char (Window win, char ch, int x, int y, char color);

/** \brief Desenha uma string na janela
 *
 * \param win Janela
 * \param str String
 * \param x Coordenada x do ponto
 * \param y Coordenada y do ponto
 * \param color Cor do caracter
 */
void window_draw_string (Window win, const char *str, int x, int y, char color);

/** \brief Desenha um inteiro na janela
 *
 * \param win Janela
 * \param num Inteiro a ser escrito
 * \param x Coordenada x do ponto
 * \param y Coordenada y do ponto
 * \param color Cor do caracter
 */
void window_draw_int (Window win, int num, int x, int y, char color);

/** \brief Desenha um retângulo na janela
 * \param win Janela
 * \param x Coordenada X do retângulo
 * \param y Coordenada Y do retângulo
 * \param w Largura do retângulo
 * \param h Altura do retângulo
 * \param color Cor do retângulo
 */
void window_draw_rect (Window win, int x, int y, int w, int h, char color);

/** Define uma callback de exibição que simplesmente desenha um XPM na janela
 * A variável data armazena os dados passados para a função
 *
 * \param NAME Nome da função gerada
 * \param XPM Código que gera o identificador do XPM
 * \param X Coordenada X onde o XPM é mostrado
 * \param Y Coordenada Y onde o XPM é mostrado
 * \param TYPE Tipo apontado pela variável data
 */
#define WINDOW_DRAW_CB_XPM(NAME,XPM,X,Y,TYPE) \
 void NAME (Window win, int x, int y, int w, int h, void *DATA) \
 { \
 	TYPE *data = (TYPE *) DATA; \
 	enum XPMID xpmid = XPM; \
	XPM xpm = xpm_get (xpmid); \
	xpm_draw (win, xpm, (X), (Y)); \
 }

/** Define uma callback de exibição que simplesmente desenha um XPM na janela
 *
 * \param NAME Nome da função gerada
 * \param XPM Código que gera o identificador do XPM
 * \param X Coordenada X onde o XPM é mostrado
 * \param Y Coordenada Y onde o XPM é mostrado
 */
#define WINDOW_DRAW_CB_XPM_ND(NAME,XPM,X,Y) \
 void NAME (Window win, int x, int y, int w, int h, void *DATA) { \
  xpm_draw (win, xpm_get (XPM), (X), (Y)); \
  }

/** Define uma callback de exibição que exibe uma animação na tela
 * A variável data armazena os dados passados para a função
 *
 * \param NAME Nome da função gerada
 * \param ANIM Animação
 * \param X Coordenada X onde o XPM é mostrado
 * \param Y Coordenada Y onde o XPM é mostrado
 * \param TYPE Tipo da variável data
 */
#define WINDOW_DRAW_CB_ANIM(NAME,ANIM,X,Y,TYPE) \
 void NAME (Window win, int x, int y, int w, int h, void *DATA) \
 { \
 	TYPE *data = (TYPE *) DATA; \
	XPM xpm = anim_continue(ANIM); \
	xpm_draw (win, xpm, (X), (Y)); \
 }


#endif /* LCOM_WINDOW_H */

